import tkinter as tk
import os
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
import csv
from PIL import Image, ImageTk
import logging
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s:%(levelname)s:%(message)s')


class MovieRatingApp:
    def __init__(self, root):
        self.root = root
        root.title("Movie Rating App")
        root.geometry("900x600")

        # -------------------- 加载电影海报 --------------------
        self.image1 = Image.open(os.path.join(os.path.dirname(__file__), 'post1_relie.jpg'))
        self.image1.thumbnail((100, 300))
        self.movie1_image = ImageTk.PhotoImage(self.image1)
        self.movie1_label = tk.Label(root, image=self.movie1_image)
        self.movie1_label.grid(row=0, column=0, padx=10, pady=10)

        self.image2 = Image.open(os.path.join(os.path.dirname(__file__), "post2_family.jpg"))
        self.image2.thumbnail((100, 300))
        self.movie2_image = ImageTk.PhotoImage(self.image2)
        self.movie2_label = tk.Label(root, image=self.movie2_image)
        self.movie2_label.grid(row=0, column=1, padx=10, pady=10)

        # -------------------- 评分下拉菜单 --------------------
        self.movie1_rating = tk.StringVar(root, value="1")
        tk.OptionMenu(root, self.movie1_rating, "1", "2", "3", "4", "5") \
            .grid(row=1, column=0, padx=10, pady=10)

        self.movie2_rating = tk.StringVar(root, value="1")
        tk.OptionMenu(root, self.movie2_rating, "1", "2", "3", "4", "5") \
            .grid(row=1, column=1, padx=10, pady=10)

        # -------------------- 类型单选 --------------------
        self.preference = tk.IntVar()
        tk.Radiobutton(root, text="动作片", variable=self.preference, value=0) \
            .grid(row=2, column=0, padx=10, pady=10)
        tk.Radiobutton(root, text="喜剧片", variable=self.preference, value=1) \
            .grid(row=2, column=1, padx=10, pady=10)

        # -------------------- 功能按钮 --------------------
        tk.Button(root, text="Confirm", command=self.confirm) \
            .grid(row=3, column=0, padx=10, pady=20)
        tk.Button(root, text="Clear", command=self.clear_plot) \
            .grid(row=3, column=1, padx=10, pady=20)
        tk.Button(root, text="Predict", command=self.predict_preference) \
            .grid(row=4, columnspan=2, padx=10, pady=20)

        self.predict_label = tk.Label(root, text="")
        self.predict_label.grid(row=5, columnspan=2, padx=10, pady=10)

        # -------------------- CSV 初始化 --------------------
        self.filename = os.path.join(os.path.dirname(__file__), 'ratings.csv')
        if not os.path.isfile(self.filename):
            with open(self.filename, 'w', newline='') as f:
                csv.writer(f).writerow(["Movie1", "Movie2", "Preference"])

        # -------------------- 绘图框架 --------------------
        self.plot_frame = tk.Frame(root)
        self.plot_frame.grid(row=0, column=2, rowspan=4, padx=10, pady=10)
        self.plot_ratings()

    # -------------------- 确认按钮：保存当前记录 --------------------
    def confirm(self):
        m1 = self.movie1_rating.get()
        m2 = self.movie2_rating.get()
        pref = self.preference.get()
        with open(self.filename, 'a', newline='') as f:
            csv.writer(f).writerow([m1, m2, pref])
        self.plot_ratings()

    # -------------------- 清除按钮：重置 CSV --------------------
    def clear_plot(self):
        with open(self.filename, 'w', newline='') as f:
            csv.writer(f).writerow(["Movie1", "Movie2", "Preference"])
        self.predict_label.config(text="")
        self.plot_ratings()

    # -------------------- 绘图：散点可视化 --------------------
    def plot_ratings(self):
        self.plot_frame.destroy()
        self.plot_frame = tk.Frame(self.root)
        self.plot_frame.grid(row=0, column=2, rowspan=4, padx=10, pady=10)

        if not os.path.isfile(self.filename):
            return
        df = pd.read_csv(self.filename)
        if df.empty:
            return

        action_df = df[df['Preference'] == 0]
        comedy_df = df[df['Preference'] == 1]

        fig, ax = plt.subplots()
        ax.grid(True)
        ax.scatter(action_df['Movie1'], action_df['Movie2'],
                   color='orange', label='Action')
        ax.scatter(comedy_df['Movie1'], comedy_df['Movie2'],
                   color='blue', label='Comedy')

        # 给每个点加坐标文字
        for _, row in action_df.iterrows():
            ax.text(row['Movie1'], row['Movie2'],
                    f"({row['Movie1']},{row['Movie2']})", fontsize=7)
        for _, row in comedy_df.iterrows():
            ax.text(row['Movie1'], row['Movie2'],
                    f"({row['Movie1']},{row['Movie2']})", fontsize=7)

        ax.set_xlabel('Movie A Rating')
        ax.set_ylabel('Movie B Rating')
        ax.set_xlim(0, 6)
        ax.set_ylim(0, 6)
        ax.legend()

        canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)
        canvas.draw()
        canvas.get_tk_widget().pack()

    # -------------------- 预测：1-NN 分类 --------------------
    def predict_preference(self):
        df = pd.read_csv(self.filename)
        if df.empty or len(df) < 1:
            self.predict_label.config(text="还没有历史数据，无法预测！")
            return

        X = df[['Movie1', 'Movie2']].values.astype(int)
        y = df['Preference'].values.astype(int)

        knn = KNeighborsClassifier(n_neighbors=1)
        knn.fit(X, y)

        new_point = np.array([[int(self.movie1_rating.get()),
                               int(self.movie2_rating.get())]])

        pred = knn.predict(new_point)
        self.predict_label.config(
            text=f"给用户推荐的电影类型: {'动作片' if pred[0] == 0 else '喜剧片'}"
        )

        # 重绘画布并标注新点与最近邻
        self.plot_ratings()
        ax = plt.gca()
        ax.scatter(new_point[:, 0], new_point[:, 1],
                   color='red', marker='x', s=150, linewidths=4, label='New user')

        dist, idx = knn.kneighbors(new_point, return_distance=True)
        nn_coord = X[idx[0][0]]
        ax.plot([new_point[0, 0], nn_coord[0]],
                [new_point[0, 1], nn_coord[1]], 'r--', linewidth=2)
        ax.legend()

        canvas = FigureCanvasTkAgg(plt.gcf(), master=self.plot_frame)
        canvas.draw()
        canvas.get_tk_widget().pack()


# -------------------- 启动 --------------------
if __name__ == "__main__":
    root = tk.Tk()
    MovieRatingApp(root)
    root.mainloop()